int sceneWidth = 1200;
int sceneHeight = 700;
  
int nClouds = 2;
Cloud[] clouds = new Cloud[nClouds];

int nBirds = 10;
Bird[] birds = new Bird[nBirds];

Sun sun;

Avion avion;

void setup() {
  size(sceneWidth, sceneHeight);
  smooth();

  for(int i = 0; i < nClouds; i++) {
    clouds[i] = new Cloud(sceneWidth, sceneHeight);
  }
  
  for(int i = 0; i < nBirds; i++) {
    birds[i] = new Bird(sceneWidth, sceneHeight);
  }
  
  sun = new Sun(sceneWidth, sceneHeight);
  
  avion = new Avion(sceneWidth, sceneHeight);
}

void draw() {
  background(153, 202, 255);
  
  sun.move();
  sun.display();
  
  // collines
  strokeWeight(2);
  stroke(50, 100, 50);
  color c = color(150, 215, 105);
  fill(c);
  ellipse(-200, sceneHeight + 70, 1500, 450);

  c = color(170, 235, 125);
  fill(c);
  ellipse(1000, sceneHeight + 170, 2500, 600);
  
  for(int i = 0; i < nClouds; i++) {
    clouds[i].move();
    clouds[i].display();
  }
  
  avion.move();
  avion.display();
  
  for(int i = 0; i < nBirds; i++) {
    birds[i].move();
    birds[i].display();
  }

}

class Variator {
  float value = 0.0;
  float direction = 0.0;
  float variationMax = 0.0;
  float accelerationMax = 0.0;
  float max = 0.0;
  float min = 0.0;
  int proba = 5; // 1 chance sur 5 que ça varie;
  
  Variator(float initMin, float initMax, float initVariationMax, float initAccelerationMax, int initProba) {
    variationMax = initVariationMax;
    accelerationMax = initAccelerationMax;
    min = initMin;
    max = initMax;
    proba = initProba;
    
    value = random(min, max);
    direction = random(-variationMax, variationMax);
  }
  
  void varie() {
     if(random(0, proba) < 1) {
       direction += random(-accelerationMax, accelerationMax);
       if(direction > variationMax) direction = variationMax;
       if(direction < -variationMax) direction = -variationMax;
     }
     value += direction;
     if(value > max) direction = -direction;
     if(value < min) direction = -direction;
  }
}

class Regular {
  float value;
  float min;
  float max;
  float speed;
  
  Regular(float initMin, float initMax, float initSpeed) {
   value = initMin;
   min = initMin;
   max = initMax;
   speed = initSpeed;
  }
  
  void varie() {
     value += speed;
     if(value > max) speed = -speed;
     if(value < min) speed = -speed;
  }
}

class CloudPrimitive {
  Variator relativeX;
  Variator relativeY;
  Variator scale;
  Variator ratioLargeurHauteur;
  Variator nuanceGris;
  
  CloudPrimitive() {
    relativeX = new Variator(-100, 100, 0.1, 0.2, 20);
    relativeY = new Variator(-40, 40, 0.1, 0.2, 20);
    scale = new Variator(80, 250, 0.5, 0.2, 20);
    ratioLargeurHauteur = new Variator(0.4, 0.9, 0.05, 10, 20);
    nuanceGris = new Variator(230, 255, 0.5, 0.1, 20);
  }
  
  void move() {
    relativeX.varie();
    relativeX.varie();
    scale.varie();
    nuanceGris.varie();
  }
  
  void display(int globalX, int globalY) {
    int gris = (int)nuanceGris.value;
    color c = color(gris, gris, gris, 200);
    fill(c);
    ellipse(globalX + (int)relativeX.value, globalY + (int)relativeY.value, (int)scale.value, (int)(scale.value * ratioLargeurHauteur.value));
  }
  
}

class Cloud {
  Variator x;
  Variator y;
  int nPrimitives;
  CloudPrimitive[] cloudPrimitives;

  Cloud(int sceneWidth, int sceneHeight) {
    x = new Variator(0, sceneWidth, 1, 0.5, 20);
    y = new Variator(0, 2 * sceneHeight / 5, 1, 0.2, 20);
    nPrimitives = (int)random(5, 12);
    cloudPrimitives = new CloudPrimitive[nPrimitives];
    
    for(int i = 0; i < nPrimitives; i++) {
      cloudPrimitives[i] = new CloudPrimitive();
    }
  }
  
  void move() {
    x.varie();
    y.varie();
    for(int i = 0; i < nPrimitives; i++) {
      cloudPrimitives[i].move();
    } 
  }

  void display() {
    noStroke();
    for(int i = 0; i < nPrimitives; i++) {
      cloudPrimitives[i].display((int)x.value, (int)y.value);
    }
  }

}

class Bird {
  Variator x;
  Variator y;

  Bird(int sceneWidth, int sceneHeight) {
    x = new Variator(0, sceneWidth, 1, 0.5, 20);
    y = new Variator(0, 2 * sceneHeight / 5, 1, 0.2, 20);
  }
  
  void move() {
    x.varie();
    y.varie(); 
  }
  
  void display() {
    //println("coucou " + x.value + " " + y.value);
    strokeWeight(1);
    stroke(0);
    int posx = (int)x.value;
    int posy = (int)y.value;
    noFill();
    arc(posx, posy, 30, 15, PI, TWO_PI-PI/2);
    arc(posx-30, posy, 30, 15, TWO_PI-PI/2, TWO_PI);
  }
}

class Sun {
  int x;
  int y;
  Regular size;
  int nRays = 20;
  Ray[] rays = new Ray[nRays];
  
  Sun(int sceneWidth, int sceneHeight) {
    x = sceneWidth - 50;
    y = 50;
    size = new Regular(150, 200, 0.2);
    
    for(int i = 0; i < nRays; i++) {
      rays[i] = new Ray(x, y);
    }
  }
  
  void move() {
    size.varie();
    
    for(int i = 0; i < nRays; i++) {
      rays[i].move((int)size.value);
    }
  }
  
  void display() {
    color c = color(255, 255, 0);
    fill(c);
    noStroke();
    int s = (int)size.value;
    ellipse(x, y, s, s);
    
    for(int i = 0; i < nRays; i++) {
      rays[i].display();
    }
  }
}

class Ray {
  int rayonSun;
  int xSun;
  int ySun;
  Variator angle;
  
  Ray(int initXSun, int initYSun) {
    xSun = initXSun;
    ySun = initYSun;
    angle = new Variator(-QUARTER_PI, 3*QUARTER_PI, 0.001, 0.05, 20);
  }
  
  void move(int rayon) {
    rayonSun = rayon;
    angle.varie(); 
  }
  
  void display() {
    stroke(255, 255, 0, 50);
    strokeWeight(10);
    noFill();
    int factorM = rayonSun - 70;
    int factorN = rayonSun + 1000;
    float cosAngle = cos(angle.value);
    float sinAngle = sin(angle.value);
    line(xSun - factorM * cosAngle, ySun + factorM * sinAngle, xSun - factorN * cosAngle, ySun + factorN * sinAngle);
  }
}

class Avion {
  float x;
  float y;
  int sceneWidth;
  PImage avionImage;
  
  Avion(int initSceneWidth, int initSceneHeight) {
   sceneWidth = initSceneWidth;
   x = initSceneWidth / 2;
   y = 50;
   avionImage = loadImage("avion.png");
  }
  
  void move() {
    x += 0.5;
    if(x > sceneWidth + 300) {
      x = -100; 
    }
    y = 50 + 20*sin(x / 20);
  }
  
  void display() {
    image(avionImage, x, (int)y, 60, 35);
    textSize(32);
    fill(255, 128, 128);
    text("Help us to travel !", x - 300, (int)y + 35);
  }
}


